
#include "common/types.h"
#include "gdt.h"
#include "hardwarecommunication/interrupts.h"
#include "common/common.h"
#include "driver/keyboard.h"
#include "driver/driver.h"
#include "driver/mouse.h"
#include <hardwarecommunication/pci.h>
#include <gui/desktop.h>
#include <gui/window.h>
#include <multitasking.h>
#include <memory/memorymanagement.h>
#include <driver/ata.h>
#include <syscallhandle.h>
#define TEXT

// ===============================================PrintfMouseEventHandler========================================

class PrintfMouseEventHandler : public MouseEventHandler
{
private:
    /* data */
public:

    void OnMouseMove(int8_t xoffset,int8_t yoffset){
         static int8_t x = 40, y = 12;
        static uint16_t* VideoMemory = (uint16_t*)0xb8000;
        VideoMemory[80 * y + x] = ((VideoMemory[80 * y + x] & 0xF000) >> 4)
                                | ((VideoMemory[80 * y + x] & 0x0F00) << 4)
                                | (VideoMemory[80 * y + x] & 0x00FF);
         x += xoffset;
         y -= yoffset;
        if(x < 0 ) x = 0;
        if(x >= 80) x = 79;
        if(y <= 0) y = 0;
        if(y >= 25) y = 24;
        
        VideoMemory[80 * y + x] = ((VideoMemory[80 * y + x] & 0xF000) >> 4)
                    | ((VideoMemory[80 * y + x] & 0x0F00) << 4)
                    | (VideoMemory[80 * y + x] & 0x00FF);


    }
    void OnMouseDown(char* str){
        printf(str);
    }
    void OnMouseUp(char* str){
        printf(str);
    }
};


// ===============================================PrintfKeyboardEventHandler========================================

class PrintfKeyboardEventHandler : public KeyboardEventHandler
{
private:
    /* data */
public:
    void OnKeyDown(char){
    printf("key down");
    }
};


void sysPrintf(char* str){

    asm volatile("int $0x80"::"a"(4),"b"(str));

}

void task1(){
    while(1){
    sysPrintf("123123\n");
    }

}

void task2(){
    while(1){
    sysPrintf("456456\n");
    }
}


typedef void(*constructor)();

extern "C" constructor start_ctors;

extern "C" constructor end_ctors;

extern "C" void callConstructors(){

    for(constructor* i = &start_ctors;i != &end_ctors;i++){
        (*i)();
    }
}

extern "C" void kernelMain(void* multiboot_structure,unsigned int magicnumber){
    cleanScreen();
    
    printf("LOAD KERNEL SUCCESS!\n");
    GlobalDescriptorTable  gdt;
    printf("SET GDT SUCCESS!\n");
    TaskManager taskManager;
    Task taskA(&gdt, &task1);
    Task taskB(&gdt, &task2);
    // taskManager.AddTask(&taskA);
    // taskManager.AddTask(&taskB);

    uint32_t* memupper = (uint32_t*)(((size_t)multiboot_structure) + 8);
    size_t heap = 10 * 1024 * 1024;
    MemoryManager memorymanager(heap,(*memupper) * 1024 - heap - 10 * 1024);

    printf("heap: 0x");
    printfHex((heap >> 24) & 0xFF);
    printfHex((heap >> 16) & 0xFF);
    printfHex((heap >> 8) & 0xFF);
    printfHex((heap >> 0) & 0xFF);

    void* allocated = memorymanager.malloc(1024);

    printf("\nallocated: 0x");
    printfHex(((uint32_t)allocated >> 24) & 0xFF);
    printfHex(((uint32_t)allocated >> 16) & 0xFF);
    printfHex(((uint32_t)allocated >> 8) & 0xFF);
    printfHex(((uint32_t)allocated >> 0) & 0xFF);
    printf("\n");


    InterruptManager interrupts(0x20, &gdt, &taskManager);
    printf("SET IDT SUCCESS!\n");
#ifdef GUI
    Desktop desktop(320, 200, 0x00, 0x00, 0xA8);
#endif
    MouseEventHandler mhandler;
    MouseDriver mouse(&interrupts,&mhandler);
    KeyboardEventHandler khandler;
    KeyBoardDriver keyBoard(&interrupts,&khandler);

    DriverManager driverManager;
    driverManager.addDriver(&mouse);
    driverManager.addDriver(&keyBoard);
    Pci pci;
    pci.SelectDriver(&driverManager,&interrupts);



    driverManager.ActivateAll();
    printf("LOAD DRIVER SUCCESS!\n");

        //interrupt 14
    Ata ata0m(0x1f0,true);
    printf("ATA Primary Master : ");
    ata0m.Identify();
    printf("\n");
    Ata ata0s(0x1f0,false);
    printf("ATA Primary Slave : ");
    ata0s.Identify();
    printf("\n");

    //interrupt 15
    Ata ata1m(0x170,true);
    ata1m.Identify();
    Ata ata1s(0x170,false);
    ata1m.Identify();
    // third:0x1E8
    // fourth: 0x168

    char* buffer = "yos hard visit success!\n";
    ata0s.Writr28(0, (uint8_t*)buffer,24);
    buffer[0] = 'm';
    ata0s.Flush();
    ata0s.Read28(0,(uint8_t*)buffer,24);
    printf(buffer);

    printf("OPEN INTERRUPT SUCCESS!\n");
    interrupts.Activate();

    
    SyscallHandler syscallHandle(&interrupts,0x80);
    sysPrintf("123123\n");





#ifdef GUI
    Vga vga;
    vga.SetMode(320, 200, 8);
    


    Window window1(&desktop, 10, 10, 20, 20, 0xA8, 0x00, 0x00);
    Window window2(&desktop, 45, 15, 30, 30, 0x00, 0xA8, 0x00);

    desktop.AddChild(&window1);
    desktop.AddChild(&window2);
    vga.FillRectangle(0, 0, 320, 200, 0x00, 0x00, 0xA8);
    vga.PutFont(0,0,55);
#endif

    while(1){

#ifdef GUI

    desktop.Draw(&vga);

#endif

    }
}
